package com.mxprojects.views
{
	import com.mxprojects.constructors.ButtonLarge;
	import com.mxprojects.constructors.CheckboxConstructor;
	import com.mxprojects.constructors.Divider;
	import com.mxprojects.constructors.InputConstructor;
	import com.mxprojects.constructors.PopupWindow;
	import com.mxprojects.constructors.SimpleTextField;
	import com.mxprojects.gui.AvatarDisplay;
	import com.mxprojects.gui.BreadCrumbs;
	import com.mxprojects.gui.DefaultDialog;
	import com.mxprojects.gui.Resizer;
	import com.mxprojects.gui.Styles;
	import com.mxprojects.io.BoardCookie;
	import com.mxprojects.io.Config;
	import com.mxprojects.io.CustomEvent;
	import com.mxprojects.io.DeepLinking;
	import com.mxprojects.io.ServerHandler;
	import com.mxprojects.io.UserControl;
	import com.mxprojects.io.Utils;
	import com.mxprojects.language.Language;
	import com.mxprojects.language.Word;
	
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.events.TextEvent;
	import flash.text.TextField;
	
	public class Register
	{
		protected static const MULTI_LINE_INPUT_FIELDS:Array = new Array(Word.SIGNATURE);
		protected static const MULTI_LINE_ROW_COUNT:int = 6;
		protected static const REQUIRED_SYMBOL:String = "<span class=\"formRequired\">*</span> ";
		protected static const POPUP_WINDOW_WIDTH:int = 300;
		protected static const POPUP_WINDOW_HEIGHT:int = 200;
		protected static const ACTION_LOAD_NETWORKS:String = "loadNetworks";
		protected static const ACTION_LOAD_USER:String = "loadUser";
		protected static const ACTION_UPDATE_USER:String = "updateUser";
		protected static const ACTION_REGISTER_USER:String = "registerUser";
		protected static const ACTION_VERIFY_USER:String = "verifyUser";
		protected static const EXTRA_FIELD_DIVIDER:String = "Ƴș";
		protected static const INPUT_CSS:String = "registerInput";
		protected static const LABEL_CSS:String = "registerLabel";
		
		protected static var inputFields:Array;
		protected static var requiredFields:Array;
		protected static var holder:Sprite = new Sprite();
		protected static var registerButton:ButtonLarge;
		protected static var largestLabel:TextField
		protected static var offset:int = 0;
		protected static var action:String;
		protected static var dataToSend:Object;
		protected static var regData:Object;
		protected static var avatarDisplay:AvatarDisplay = new AvatarDisplay();
		protected static var avatarUploader:Sprite = new Sprite();
		protected static var sectionTitle:SimpleTextField;
		protected static var requiredLegend:SimpleTextField;
		protected static var divider:Divider;
		protected static var leftColumnBottomY:int;
		
		private static var ageCheck:CheckboxConstructor;
		private static var serverHandler:ServerHandler = new ServerHandler();
		private static var regPopup:PopupWindow;
		private static var termsPopup:PopupWindow;
		
		public function Register(){	}
		
		public static function load():void {
			//get the social networks from the server
			dataToSend = new Object();
			dataToSend.action = ACTION_LOAD_NETWORKS;
			serverHandler.transmitData("registeruser.php", dataToSend);
			serverHandler.listenForData(showRegister);
			
			//clear the forum			
			MXP3.clearBoard();
			
			//resize the page if we need to
			Resizer.resizeContent();
		}
		
		public static function verify(username:String, key:String):void {
			//check to make sure everything is a-ok and send it along
			var data:Object = new Object();
			data.action = ACTION_VERIFY_USER;
			data.username = username;
			data.key = key;
			data.guestGroupID = Config.GUEST_GROUP_ID;
			
			var server:ServerHandler = new ServerHandler();
			server.transmitData("registeruser.php", data);
			server.listenForData(handleVerify);
		}
		
		private static function showRegister(event:CustomEvent = null):void {
			if(event != null){
				regData = event.getServerData();
			}
			
			//tell the board where we are
			MXP3.currentLocation = Word.REGISTER;
			BreadCrumbs.createCrumbs(0, "", 0, "", Word.REGISTER, Language.main(Word.REGISTER));
			DeepLinking.setTitle(Language.main(Word.REGISTER));
			
			//create a holder to hold all of the input boxes
			clearHolder();
			
			//build up what the input fields should be
			defineInputs();
			
			//see how many extra form fields we have
			defineExtraInputs(regData);
			
			//show everything
			displayRegister();
			
			//set the action to what it should be
			action = ACTION_REGISTER_USER;
						
			//at it to the stage
			MXP3.addContent(holder);
			MXP3.addContent(registerButton);
			
			//move stuff around if we need to
			//resize();
		}
		
		private static function handleVerify(event:CustomEvent):void {
			var data:Object = event.getServerData();
			
			switch(data.output){
				case "mysqlError":
					DefaultDialog.show(data.mysqlError);
				break;
				
				case "matchError":
					DefaultDialog.show(Language.main(Word.ERROR_VERIFY_MATCH));
				break;
				
				case "alreadyVerified":
					DefaultDialog.show(Language.main(Word.ERROR_VERIFY_ALREADY));
				break;
				
				case "success":
					DefaultDialog.show(Language.main(Word.MESSAGE_VERIFY_SUCCESS), true, Word.SUCCESS);
				break;
			}
		}
		
		private static function displayRegister():void {						
			//create the title to show where we are
			createTitle(Language.main(Word.REGISTER) + InputConstructor.LABEL_SEPARATOR + Config.BOARD_NAME);
			
			//build the input boxes
			buildInputBoxes();
			
			//create a little required legend to the top right
			createLegend();
			
			//add the thing to upload an avatar
			if(Config.ADD_AVATAR_ON_REGISTER == 1){
				//if we can add an avatar on registration
				createAvatar();
			}
			
			//add the age checker - REQUIRED
			ageCheck = new CheckboxConstructor(REQUIRED_SYMBOL + Language.main(Word.MESSAGE_AGREE_TO_TERMS), Word.MESSAGE_AGREE_TO_TERMS, false, termsLink);
			ageCheck.y = Math.round(holder.height + Config.TEXT_PADDING * 3);
			ageCheck.x = Math.round(largestLabel.width);
			holder.addChild(ageCheck);
			
			//slap the divider and button on here
			createDividerAndButton(Language.main(Word.REGISTER));
		}
		
		protected static function submit(event:MouseEvent):void {
			//start collecting data
			dataToSend = new Object();
			dataToSend.action = action;
			dataToSend.abImgDir = Config.ABSOLUTE_INSTALL_PATH + Config.IMAGE_DIRECTORY + Config.AVATAR_UPLOAD_SUB_DIRECTORY;
			dataToSend.guestGroupID = Config.GUEST_GROUP_ID;
			dataToSend.divider = EXTRA_FIELD_DIVIDER;
			dataToSend.defaultUserTitle = Config.DEFAULT_USER_TITLE;
			
			//check if there is data in the required fields
			if(!isRequiredDataOk(inputFields)){
				return;
			}
			if(!isRequiredDataOk(MULTI_LINE_INPUT_FIELDS)){
				return;
			}
			
			//if they are logged in and updating the profile, send along the userID
			if(BoardCookie.getUser() != "undefined" && BoardCookie.getUser() != null){
				dataToSend.userID = BoardCookie.getUserID();
			}
			
			//make sure the passwords match each other
			var passwordMatch:Boolean;
			if(action == ACTION_UPDATE_USER){
				passwordMatch = (getInputValue(Word.CHANGE_PASSWORD) == getInputValue(Word.CONFIRM_PASSWORD));
			}else{
				passwordMatch = (getInputValue(Word.PASSWORD) == getInputValue(Word.CONFIRM_PASSWORD));
			}
			if(!passwordMatch){
				//throw an error and back out
				DefaultDialog.show(Language.main(Word.ERROR_PASSWORD_MISMATCH));
				return;
			}
		
			//if there is an avatar send it along
			if(avatarDisplay.getAvatarFile() != null){
				dataToSend.avatar = avatarDisplay.getAvatarFile().getFileName();
			}
				
			//make the default url profile because regiser needs an age checker
			var url:String = "profile.php";
			if(action == ACTION_REGISTER_USER){
				//change up the URL
				url = "registeruser.php";
				
				//see if the 13 or over is checked
				if(!ageCheck.isChecked){
					//toss out another error
					DefaultDialog.show(Language.main(Word.ERROR_AGE_VERIFICATION));
					return;
				}
				
				//send along the welcome message
				dataToSend.boardName = Config.BOARD_NAME;
				dataToSend.boardEmail = Config.BOARD_EMAIL;
				dataToSend.activation = Language.main(Word.ACTIVATION);
				dataToSend.welcomeMessage = Language.main(Word.MESSAGE_WELCOME_EMAIL);
				dataToSend.installDirectory = Config.INSTALL_DIRECTORY;
			}
			
			//send off the data!
			serverHandler.transmitData(url, dataToSend);
			serverHandler.listenForData(showResults);
			
			//make sure they don't click the button twice
			registerButton.enabled = false;
		}
		
		protected static function defineInputs(isProfile:Boolean = false):void {
			//these are the basic inputs needed to register/update
			if(isProfile){
				inputFields = new Array(Word.USERNAME, Word.CHANGE_PASSWORD, Word.CONFIRM_PASSWORD, Word.EMAIL, Word.LOCATION, Word.WEBSITE);
				requiredFields = new Array(Word.EMAIL);
			}else{
				inputFields = new Array(Word.USERNAME, Word.PASSWORD, Word.CONFIRM_PASSWORD, Word.EMAIL, Word.LOCATION, Word.WEBSITE);
				requiredFields = new Array(Word.USERNAME, Word.PASSWORD, Word.CONFIRM_PASSWORD, Word.EMAIL);
			}
		}
		
		protected static function defineExtraInputs(serverData:Object):void {
			//this will handle any social networking stuff that's added to register/profile
			var totalNetworks:int = serverData.totalNetworks;
			for(var i:int = 0; i < totalNetworks; i++){
				//this will push the extra fields in. We need to flag them as being special so we add a divider
				inputFields.push(serverData["networkID" + i] + EXTRA_FIELD_DIVIDER + 
								 serverData["networkLanguage" + i] + EXTRA_FIELD_DIVIDER + 
								 serverData["networkValue" + i]);
			}
		}
		
		public static function resize():void {
			//move the stuff around
//			if(holder != null && registerButton != null){
//				holder.x = Math.floor((MXP3.wStage/2) - (holder.width/2) - (largestLabel.width/2) + offset);
//				registerButton.x = Math.floor((MXP3.wStage/2) - (registerButton.width/2));
//			}
		}
		
		protected static function clearHolder():void {
			//empty the holder for new stuff
			var holderChildren:int = holder.numChildren;
			for(var i:int = 0; i < holderChildren; i++){
				holder.removeChildAt(0);
			}
		}
		
		protected static function createTitle(text:String):void {
			//put a little text label
			var registerText:String = "<span class=\"registerTitle\">" + text + "</span>";
			if(sectionTitle == null){
				sectionTitle = new SimpleTextField(registerText);
				sectionTitle.x = Styles.css.getStyle(".registerTitle").x;
				sectionTitle.y = Styles.css.getStyle(".registerTitle").y;
			}else{
				sectionTitle.htmlText = registerText;
			}
			
			MXP3.addContent(sectionTitle);
			
			holder.y = sectionTitle.y + sectionTitle.height + Config.TEXT_PADDING;
			holder.x = sectionTitle.x;
		}
		
		protected static function createLegend():void {
			//put a little text box that is a legend for the required fields
			var legendText:String = "<span class=\"registerRequiredLegend\">" + REQUIRED_SYMBOL + Language.main(Word.REQUIRED_FIELDS) + "</span>";
			if(requiredLegend == null){
				requiredLegend = new SimpleTextField(legendText);
				requiredLegend.x = holder.width - requiredLegend.width + 4;
				requiredLegend.y = Math.round(sectionTitle.y + sectionTitle.height/2 - requiredLegend.height/2);
			}else{
				requiredLegend.htmlText = legendText;
			}
			
			MXP3.addContent(requiredLegend);
		}
		
		protected static function createAvatar(url:String = ""):void {
			//get the width of the input box
			var input:InputConstructor = holder.getChildByName(Word.EMAIL) as InputConstructor;
			
			var avatarChildren:int = avatarUploader.numChildren;
			if(avatarChildren > 0){
				for(var i:int = 0; i < avatarChildren; i++){
					avatarUploader.removeChildAt(0);
				}
			}
			
			//this will fix any legacy avatars that are trying to pull from a website instead of a local install
			if(url != "" && url.substr(0, 7) != "http://" && url != "null"){
				//tack on the image directory and set it up
				url = Config.INSTALL_DIRECTORY + Config.IMAGE_DIRECTORY + Config.AVATAR_UPLOAD_SUB_DIRECTORY + url;
			}else{
				url = "";
			}
			
			avatarUploader = avatarDisplay.setupAvatarUploader(input.inputBox.width, url);
			avatarUploader.x = largestLabel.width;
			avatarUploader.y = leftColumnBottomY;
			
			holder.addChild(avatarUploader);
		}
		
		protected static function createDividerAndButton(buttonText:String):void {
			//get the x of the input box
			var input:InputConstructor = holder.getChildByName(Word.EMAIL) as InputConstructor;
			
			//add a divider
			if(divider == null){
				divider = new Divider(1, 0xffcc00);
				Styles.setProperties(divider, ".registerDivider");
				divider.x = input.x + input.inputBox.x;
				divider.y = Math.round(holder.height + Config.TEXT_PADDING*2);
				divider.width = holder.width - (input.x + input.inputBox.x);
			}
			holder.addChild(divider);
			
			//put a register button on the stage
			registerButton = new ButtonLarge(buttonText, submit);
			registerButton.y = Math.round(holder.y + holder.height + Config.TEXT_PADDING * 2);
			registerButton.x = divider.x + holder.x;
		}
		
		private static function isRequiredDataOk(inputArray:Array):Boolean {
			//this will take an array and make sure there are no required labels
			for(var i:int = 0; i < inputArray.length; i++){
				var input:InputConstructor = holder.getChildByName(inputArray[i]) as InputConstructor;
				if(requiredFields.indexOf(input.name) != -1 && input.inputBox.text == ""){
					//throw an error and end it right here
					DefaultDialog.show(Language.main(Word.ERROR_REQURED_FIELDS));
					return false;
				}
				
				//if everything checks out let's populate the dataToSend
				dataToSend[inputArray[i]] = input.inputBox.text;
			}
			
			//after it's all done make sure we say it was fine
			return true;
		}
		
		private static function showResults(event:CustomEvent):void {
			regData = event.getServerData();
			
			//let's see what the server said
			switch(regData.output){
				case "emailFail":
					DefaultDialog.show(Language.main(Word.ERROR_VALID_EMAIL));
					registerButton.enabled = true;
				break;
				
				case "emailInUse":
					DefaultDialog.show(Language.main(Word.ERROR_DUPLICATE_EMAIL));
					registerButton.enabled = true;
				break;
				
				case "usernameInUse":
					DefaultDialog.show(Language.main(Word.ERROR_DUPLICATE_USERNAME));
					registerButton.enabled = true;
				break;
				
				case "mysqlError":
					DefaultDialog.show(regData.mysqlError);
					registerButton.enabled = true;
				break;
				
				case "okay":
					
					var popupTitle:String = Language.main(Word.WELCOME);
					var popupText:String = Language.main(Word.MESSAGE_WELCOME_REGISTER);
					
					if(action == ACTION_REGISTER_USER){
						//log them in
						UserControl.login(dataToSend.username, dataToSend.password);
					}else if(action == ACTION_UPDATE_USER){
						popupTitle = Language.main(Word.SUCCESS);
						popupText = Language.main(Word.MESSAGE_PROFILE_UPDATED);
						
						//see if they changed the password
						if(regData.passwordChange != undefined){
							//set the board cookie to know what's up
							BoardCookie.setPassword(regData.passwordChange);
						}
					}
					
					//popup a window saying it was all good
					regPopup = new PopupWindow(POPUP_WINDOW_WIDTH, POPUP_WINDOW_HEIGHT, popupTitle, closePopup, false);
					
					//throw some welcome text on the popup
					regPopup.createTextBlock(popupText, closePopup);
				break;
			}
		}
		
		private static function termsLink(event:TextEvent):void {
			//create a popup and populate a text block
			termsPopup = new PopupWindow(POPUP_WINDOW_WIDTH, POPUP_WINDOW_HEIGHT, Language.main(Word.TERMS_AND_CONDITIONS), closeTerms, false);
			termsPopup.createTextBlock(Language.main(Word.MESSAGE_TERMS_AND_CONDITIONS), closeTerms);
		}
		
		private static function closePopup(event:MouseEvent = null):void {
			if(regPopup != null){
				regPopup.removeFromStage();
				regPopup = null;
				//clean up any left over vars
				avatarDisplay.cleanUp();
				
				//send them to the main page
				DeepLinking.setLink(Word.FORUMS, DeepLinking.createLinkArray());
			}
		}
		
		private static function closeTerms(event:MouseEvent = null):void {
			if(termsPopup != null){
				termsPopup.removeFromStage();
				termsPopup = null;
			}
		}
		
		private static function getInputValue(name:String):String {
			var input:InputConstructor = holder.getChildByName(name) as InputConstructor;
			return input.getValue();
		}
		
		/************************************************************************
		 * this will take the array, divide in half and put the stuff on the stage
		 * if there are any multi-line boxes it'll stretch it out to the right 
		 * size and place them below the other inputs
		 ************************************************************************/
		
		protected static function buildInputBoxes(prePopulateData:Object = null):void {						
			//loop through the array and build
			for(var i:int = 0; i < inputFields.length; i++){
				//build the input box
				var input:InputConstructor;
				var defaultText:String = "";
				var usernameEdit:Boolean = true;
				
				//build the input label
				var label:String = Language.main(inputFields[i]);
				if(requiredFields.indexOf(inputFields[i]) != -1){
					label = REQUIRED_SYMBOL + Language.main(inputFields[i]);
				}
				
				//check to see if any extra inputs are in the mix
				if(inputFields[i].indexOf(EXTRA_FIELD_DIVIDER) != -1){
					var chunks:Array = inputFields[i].split(EXTRA_FIELD_DIVIDER);
					label = Language.extra(chunks[1]);
					defaultText = chunks[2];
				}

				//if we have data to pre-populate do that here
				if(prePopulateData != null){
					if(prePopulateData[inputFields[i]] != undefined){
						defaultText = prePopulateData[inputFields[i]];
					}
					
					//since we must be in profile modez we can't edit the username
					usernameEdit = false;
				}
				
				//check for username so that they can't put odd chars in the name
				if(inputFields[i] == Word.USERNAME){
					//check if we are in profile mode and disale the required symbol beside the username
					if(!usernameEdit){
						label = Language.main(inputFields[i]);
					}
					input = new InputConstructor(label, defaultText, i + 100, false, 1, LABEL_CSS, INPUT_CSS, 
												 Config.MAX_USERNAME_LENGTH, Config.USERNAME_RESTRICTED_CHARS, usernameEdit);
				}else{
					input = new InputConstructor(label, defaultText, i + 100, false, 1, LABEL_CSS, INPUT_CSS);
				}

				//if it's a password style then manually set a password type. I'll need to fix this later
				if(inputFields[i] == Word.PASSWORD || inputFields[i] == Word.CONFIRM_PASSWORD || inputFields[i] == Word.CHANGE_PASSWORD){	
					input.inputBox.displayAsPassword = true;
				}

				//add it to the stage
				input.name = inputFields[i];
				holder.addChild(input);
			}

			//after everything is done, position them
			positionInputBoxes(prePopulateData);
		}
		
		private static function positionInputBoxes(prePopulateData:Object):void {
			//setup a var for column padding
			var columnSplitPoint:int = Math.ceil(inputFields.length / 2);
			var nextX:int = 0;
			var nextY:int = 0;
			var largestInput:InputConstructor = Utils.getLargestInputConstructor(holder);
			var firstInput:InputConstructor;
			var lastInput:InputConstructor;
			
			//set the shared var
			largestLabel = largestInput.inputLabel;
			
			for(var i:int = 0; i < inputFields.length; i++){
				//get a reference to the input from the holder
				var input:InputConstructor = holder.getChildByName(inputFields[i]) as InputConstructor;
				
				//see if we need to go to the next column
				if(i == columnSplitPoint){
					leftColumnBottomY = nextY + Config.TEXT_PADDING;
					nextY = 0;
					nextX = largestInput.width + Config.COLUMN_PADDING;
				}
				
				//move it where it needs to go					
				input.x = largestLabel.width - input.inputLabel.width + nextX;					
				input.y = nextY;
				nextY += input.height + Config.TEXT_PADDING/2;
				
				//if this was the first one then set it
				if(i == 0){
					firstInput = input;	
				}
				
				//same for last
				if(i == inputFields.length - 1){
					lastInput = input;
				}
			}
			
			//after everything is there build up the multiline ones
			if(buildMultiLineInputBoxes(firstInput, lastInput, prePopulateData)){
				//get the scroller width to offset stuff by
				var scrollInput:InputConstructor = holder.getChildByName(MULTI_LINE_INPUT_FIELDS[0]) as InputConstructor;
				var scroller:MovieClip = scrollInput.getChildByName("scroller") as MovieClip;
				offset = Math.floor(scroller.width - (scroller.width / 2));
			}
			
			//center everything
			//holder.x = Math.floor((MXP3.wStage/2) - (holder.width/2) - (largestLabel.width/2) + offset);
		}
		
		private static function buildMultiLineInputBoxes(firstInputBox:InputConstructor, lastInputBox:InputConstructor, prePopulateData:Object):Boolean {
			//this will continue on after the single lines are positioned
			var nextY:int = leftColumnBottomY;
			
			for(var i:int = 0; i < MULTI_LINE_INPUT_FIELDS.length; i++){
				//build the input label
				var label:String = Language.main(MULTI_LINE_INPUT_FIELDS[i]);
				if(requiredFields.indexOf(MULTI_LINE_INPUT_FIELDS[i]) != -1){
					label = REQUIRED_SYMBOL + Language.main(MULTI_LINE_INPUT_FIELDS[i]);
				}
				
				//if we have data to pre-populate do that here
				var defaultText:String = "";
				if(prePopulateData != null){
					if(prePopulateData[MULTI_LINE_INPUT_FIELDS[i]] != undefined){
						defaultText = prePopulateData[MULTI_LINE_INPUT_FIELDS[i]];
					}
				}
				
				//build the input box
				//var inputWidth:int = lastInputBox.x + lastInputBox.inputBox.width - lastInputBox.inputBox.x;
				var input:InputConstructor = new InputConstructor(label, defaultText, i + inputFields.length + 100, false, 
																  MULTI_LINE_ROW_COUNT, LABEL_CSS, INPUT_CSS);
				input.name = MULTI_LINE_INPUT_FIELDS[i];
				input.x = lastInputBox.inputLabel.width - input.inputLabel.width + lastInputBox.x;
				input.y = nextY;
				
				nextY += input.height + Config.TEXT_PADDING/2;
				
				//input.changeWidth(lastInputBox.x + lastInputBox.inputBox.width - lastInputBox.inputBox.x);
				
				//add it to the stage
				holder.addChild(input);
			}
			
			//report back to see if we need to offset by the width of the scroller
			if(MULTI_LINE_INPUT_FIELDS.length > 0){
				return true;
			}else{
				return false;
			}
		}
	}
}